package date

import (
	"time"
)

const (
	DateTimeLayout = "2006-01-02 15:04:05"
	DateLayout     = "2006-01-02"
	TimeLayout     = "15:04:05"
)

const (
	YEAR = iota
	MONTH
	DAY
	HOUR
	MINUTE
	SECOND
)

// DateTime time.Time 包装类
type DateTime struct {
	t time.Time
}

func New() *DateTime {
	return &DateTime{t: time.Now()}
}

func Now() string {
	return time.Now().Format(DateTimeLayout)
}

func NowMs() int64 {
	return time.Now().UnixMilli()
}

func (d *DateTime) Year() int {
	return d.t.Year()
}

func (d *DateTime) Month() int {
	return int(d.t.Month())
}

func (d *DateTime) Day() int {
	return d.t.Day()
}

/* ---- format function ---- */

// Format formats the time
func (d *DateTime) Format(layout string) string {
	return d.t.Format(layout)
}

func (d *DateTime) FormatDateTime() string {
	return d.Format(DateTimeLayout)
}

func (d *DateTime) FormatDate() string {
	return d.Format(DateLayout)
}

func (d *DateTime) FormatTime() string {
	return d.Format(TimeLayout)
}

/* ---- parse function ---- */

func ParseDateTime(value string) *DateTime {
	time, _ := time.ParseInLocation(DateTimeLayout, value, time.Local)
	return &DateTime{t: time}
}

func ParseDate(value string) *DateTime {
	time, _ := time.ParseInLocation(DateLayout, value, time.Local)
	return &DateTime{t: time}
}

// Offset 计算指定日期累加指定天数后的日期
func (d *DateTime) Offset(field int, offset int) *DateTime {
	newD := &DateTime{t: time.Date(d.t.Year(), d.t.Month(), d.t.Day(), d.t.Hour(), d.t.Minute(), d.t.Second(), d.t.Nanosecond(), d.t.Location())}
	switch field {
	case YEAR:
		newD.t = newD.t.AddDate(offset, 0, 0)
	case MONTH:
		newD.t = newD.t.AddDate(0, offset, 0)
	case DAY:
		newD.t = newD.t.AddDate(0, 0, offset)
	case HOUR:
		newD.t = newD.t.Add(time.Hour * time.Duration(offset))
	case MINUTE:
		newD.t = newD.t.Add(time.Minute * time.Duration(offset))
	case SECOND:
		newD.t = newD.t.Add(time.Second * time.Duration(offset))
	default:
		panic("illegal argument `field`")
	}
	return newD
}

// BeginOfMonth 获取某月的开始时间
func BeginOfMonth(d *DateTime) *DateTime {
	d.Offset(MONTH, -d.Day()+1)
	return d.BeginOfDay()
}

// EndOfMonth 获取某月最后一天
func EndOfMonth(d *DateTime) *DateTime {
	d.Offset(MONTH, 1)
	d.Offset(DAY, -1)
	return d.EndOfDay()
}

// BeginOfDay 将日期设置0点
func (d *DateTime) BeginOfDay() *DateTime {
	t := time.Date(d.Year(), time.Month(d.Month()), d.Day(), 0, 0, 0, 0, d.t.Location())
	return &DateTime{t: t}
}

// EndOfDay 将日期设置 23:59:59
func (d *DateTime) EndOfDay() *DateTime {
	t := time.Date(d.Year(), time.Month(d.Month()), d.Day(), 23, 59, 59, 0, d.t.Location())
	return &DateTime{t: t}
}
